package zoran.wang.utils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.junit.Test;
import org.springframework.stereotype.Component;

import javax.sound.midi.Soundbank;
import java.util.Arrays;

/**
 * description：日志工具类
 *
 * @author wangzhuo
 * @date 2022/3/19 19:10
 * @Email zoranwang@yeah.net
 */
@Component
@Aspect//切面类，包含通知代码的类
public class LogUtils {

    //切入点表达式的复用
    @Pointcut(value = "execution(* zoran.wang.calculate.impl.Calculator.*(..))")
    private void pointcut() {
    }

    /**
     * 前置通知
     *
     * @param joinPoint
     */
    @Before("pointcut()")
    public static void logBefore(JoinPoint joinPoint) {
        System.out.println("前置通知..." +
                "方法名:" + joinPoint.getSignature().getName() +
                ",参数:" + Arrays.asList(joinPoint.getArgs()));
    }

    @After("pointcut()")
    public static void after(JoinPoint joinPoint) {
        System.out.println("后置通知..." +
                "方法名:" + joinPoint.getSignature().getName() +
                ",参数:" + Arrays.asList(joinPoint.getArgs()));
    }

    /**
     * 返回通知
     *
     * @param joinPoint
     */
    @AfterReturning(value = "pointcut()", returning = "result")
    public static void logAfterReturning(JoinPoint joinPoint, Object result) {
        System.out.println("返回通知..." +
                "方法名:" + joinPoint.getSignature().getName() +
                ",参数:" + Arrays.asList(joinPoint.getArgs()) +
                ",返回值:" + result);
    }

    /**
     * 异常通知
     *
     * @param joinPoint
     */
    @AfterThrowing(value = "pointcut()", throwing = "e")
    public static void logAfterThrowing(JoinPoint joinPoint, Exception e) {
        System.out.println("异常通知..." + joinPoint +
                "方法名:" + joinPoint.getSignature().getName() +
                ",参数:" + Arrays.asList(joinPoint.getArgs()) +
                ",异常:" + e);
    }

    /**
     * 环绕通知
     * 1. 使用ProceedingJoinPoint，执行方法
     * 2. 一定要返回返回值
     * 3. 一定要抛出异常
     * 4. 环绕通知优先于普通通知
     *
     * @param joinPoint 用于执行方法和获取参数
     */
    @Around("pointcut()")
    public static Object around(ProceedingJoinPoint joinPoint) {
        Object result = null;

        try {
            System.out.println("环绕前置..." +
                    "方法名:" + joinPoint.getSignature().getName() +
                    ",参数:" + Arrays.asList(joinPoint.getArgs()));
            Object[] args = joinPoint.getArgs();
            if (args != null && args.length > 0) {
                result = joinPoint.proceed(args);

            }else{
                result = joinPoint.proceed();

            }

        } catch (Throwable e) {
            System.out.println("环绕异常..." +
                    "方法名:" + joinPoint.getSignature().getName() +
                    ",参数" + joinPoint.getArgs() +
                    ",异常" + e);
            e.printStackTrace();

        } finally {
            System.out.println("环绕后置..." +
                    "方法名:" + joinPoint.getSignature().getName() +
                    ",参数:" + Arrays.asList(joinPoint.getArgs()));

        }

        System.out.println("环绕返回..." +
                "方法名:" + joinPoint.getSignature().getName() +
                ",参数:" + Arrays.asList(joinPoint.getArgs()) +
                ",返回值:" + result);
        return result;
    }

}
